home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Tools / dbmbuild / dbmbuild.c next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  13.7 KB  |  743 lines

  1. /* dbmbuild: build the database of information */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Tools/dbmbuild/RCS/dbmbuild.c,v 6.0 1991/12/18 20:29:34 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Tools/dbmbuild/RCS/dbmbuild.c,v 6.0 1991/12/18 20:29:34 jpo Rel $
  9.  *
  10.  * $Log: dbmbuild.c,v $
  11.  * Revision 6.0  1991/12/18  20:29:34  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. /* ---------------------------------------------------------------------------
  19.  
  20.  
  21.     Database builder for PP address database
  22.  
  23.     Command line:
  24.         dbmbuild [-flags] [outfile]
  25.  
  26.         where flags are:
  27.         d   -   debugging output
  28.         v   -   verbose output
  29.         k   -   keep going if a table is missing
  30.         n   -   don't make a new database file
  31.  
  32.     output-file is name of EXISTING dbm file to insert entires.
  33.     Note it is two files, an output-file.dir and an output-file.pag.
  34.  
  35. --------------------------------------------------------------------------- */
  36.  
  37.  
  38. #include        "head.h"
  39. #include        "util.h"
  40. #include        "chan.h"
  41. #include        "dbase.h"
  42. #include     "sys.file.h"
  43. #include        <varargs.h>
  44.  
  45. extern int      errno;
  46. extern char     *tbldfldir,
  47.         *ppdbm;
  48.  
  49. #ifdef GDBM
  50. GDBM_FILE    thedb;
  51. #define store(x,y)    gdbm_store (thedb, x, y, GDBM_REPLACE)
  52. #define fetch(x)    gdbm_fetch (thedb, x)
  53. #else
  54. #ifndef GCC_DBM_OK
  55. #if sparc && defined(__GNUC__)    /* work around bug in gcc 1.37 sparc version */
  56.  #error GCC and dbm do not get along on a sparc - compile with cc.
  57. #endif
  58. #endif
  59. #endif
  60.  
  61. #ifdef NDBM
  62. DBM             *thedb;
  63. #define         store(x,y)      dbm_store (thedb, (x), (y), DBM_REPLACE)
  64. #define         fetch(x)        dbm_fetch (thedb, (x))
  65. #endif
  66.  
  67.  
  68. int             error,
  69.         Debug,
  70.         Verbose,
  71.         newflag = 1,
  72.         keepgoing;
  73.  
  74. char            dbfile [128],
  75.         *dblock;
  76.  
  77. static char *myname;
  78. static short    tb_nopen;   /* -- no of opened file descriptors -- */
  79. void    adios (), advise ();
  80.  
  81. static int theinit (), theend ();
  82. static int dbfinit (), dbfclose ();
  83. static int process ();
  84. static int install ();
  85. static int prdatum ();
  86. static int check ();
  87. static int tb_open (), tb_close (), tb_free ();
  88. static void cleanup ();
  89.  
  90. /* ---------------------  Begin  Routines  -------------------------------- */
  91.  
  92.  
  93. /*
  94. Process arguments, set flags and invoke file processing.
  95. then clean up and exit properly.
  96. */
  97.  
  98.  
  99. main (argc, argv)
  100. char                    **argv;
  101. {
  102.     register Table      *tp;
  103.     char                *p,
  104.     *outfile = NULLCP;
  105.     int                 ind;
  106.     int        opt;
  107.     extern char *optarg;
  108.     extern int optind;
  109.  
  110.     myname = argv[0];
  111.     sys_init (myname);
  112.  
  113.     while ((opt = getopt (argc, argv, "dknv")) != EOF) {
  114.         switch (opt) {
  115.             case 'd':
  116.             Debug++;
  117.             break;
  118.             case 'k':
  119.             keepgoing++;
  120.             break;
  121.             case 'n':
  122.             newflag = 0;
  123.             break;
  124.             case 'v':
  125.             Verbose++;
  126.             break;
  127.             default:
  128.             adios (NULLCP, "Usage: %s [-vnkd] [database]", myname);
  129.         }
  130.     }
  131.  
  132.     if (optind < argc)
  133.         optarg = argv[optind++];
  134.  
  135.     /* -- use default database -- */
  136.  
  137.     if (outfile == NULLCP) {
  138.         if (!isstr (ppdbm)) {
  139.             adios (NULLCP,
  140.                    "no default data base, in 'ppdbm' variable");
  141.         }
  142.         outfile = ppdbm;
  143.     }
  144.  
  145.  
  146.     /* -- check for existence first -- */
  147.  
  148.     error = 0;
  149.  
  150.     if (optind >= argc) {
  151.  
  152.         for (ind = 0; ch_all[ind] != NULLCHAN; ind++) {
  153.             if (ch_all[ind] -> ch_table != NULLTBL)
  154.                 error += check (ch_all[ind] -> ch_table);
  155.  
  156.             if (Debug)
  157.                 fprintf (stderr, "ch_show = '%s' - %d\n",
  158.                      ch_all[ind] -> ch_show, error);
  159.         }
  160.  
  161.  
  162.         for (ind = 0; (tp = tb_all[ind]) != NULLTBL; ind++) {
  163.             error += check (tp);
  164.             if (Debug)
  165.                 fprintf (stderr, "tb_show = '%s' - %d\n",
  166.                      tp -> tb_show, error);
  167.         }
  168.     }
  169.     else {
  170.         int    ac = optind;
  171.         while (ac < argc) {
  172.             if ((tp = tb_nm2struct (argv[ac++])) == NULLTBL) {
  173.                 advise (NULLCP, "Table '%s' is unknown",
  174.                     argv[ac - 1]);
  175.                 error++;
  176.             }
  177.             error += check (tp);
  178.         }
  179.     }
  180.  
  181.     if (error)
  182.         adios (NULLCP, "Some tables are missing.  dbmbuild aborted.");
  183.  
  184.     getfpath (tbldfldir, outfile, dbfile);
  185.  
  186.     if (Verbose || Debug) 
  187.         fprintf (stderr, 
  188. "database info:\n\ttables from %s\n\tdatabase = %s{.dir,.pag}\n\tpath = %s\n",
  189.              tbldfldir, outfile, dbfile);
  190.  
  191.     dblock = multcat (dbfile, ".lck", NULLCP);
  192.  
  193.     (void) close (creat (dblock, 0444 ));
  194.  
  195.     if (!theinit (newflag))
  196.         cleanup (NOTOK);
  197.  
  198.     if (optind >= argc) {
  199.  
  200.         /* -- process for real! -- */
  201.  
  202.         for (ind = 0; ch_all[ind] != NULLCHAN; ind++)
  203.             process (ch_all[ind] -> ch_table);
  204.  
  205.  
  206.         for (ind = 0; (tp = tb_all[ind]) != NULLTBL; ind++) {
  207.  
  208.             /* -- in case table used by chan -- */
  209.  
  210.             if (tp -> tb_fp != (FILE *)EOF) {
  211.                 if (Debug)
  212.                     fprintf (stderr, "Table '%s'\n", tp -> tb_name);
  213.                 process (tp);
  214.             }
  215.         }
  216.  
  217.     }
  218.     else
  219.         while (optind < argc) {
  220.  
  221.             if ((tp = tb_nm2struct (argv[optind++])) == NULLTBL) {
  222.                 (void) fflush (stdout);
  223.                 adios (NULLCP, "Table '%s' is unknown",
  224.                        argv[optind-1]);
  225.             }
  226.             process (tp);
  227.         }
  228.  
  229.     cleanup (theend (newflag));
  230. }
  231.  
  232.  
  233. /* ---------------------  Static  Routines  ------------------------------- */
  234.  
  235.  
  236.  
  237.  
  238. static int theinit (new)   /* -- initialize the dbm files -- */
  239. int             new;
  240. {
  241.     char        tmpfile [100];
  242.  
  243.  
  244.     /* -- start with fresh files -- */
  245.  
  246.     if (new) {
  247.     if (Verbose || Debug)
  248.         fprintf (stderr, "Temporary database:  %s$\n", dbfile);
  249. #ifdef DBM
  250.     (void) sprintf (tmpfile, "%s$.pag", dbfile);
  251.  
  252.     if (Debug)
  253.         fprintf (stderr, "creating '%s'\n", tmpfile);
  254.  
  255.  
  256.     if (close (creat (tmpfile, 0644)) < 0)
  257.         adios (tmpfile, "could not creat");
  258.  
  259.     (void) chmod (tmpfile, 0644);   /* -- in case umask screwed us -- */
  260.  
  261.     (void) sprintf (tmpfile, "%s$.dir", dbfile);
  262.  
  263.     if (Debug)
  264.         fprintf (stderr, "creating '%s'\n", tmpfile);
  265.  
  266.  
  267.     /* -- create and/or zero the file -- */
  268.  
  269.     if (close (creat (tmpfile, 0644)) < 0)
  270.         adios (tmpfile, "could not creat");
  271.  
  272.     (void) chmod (tmpfile, 0644);   /* -- in case umask screwed us -- */
  273. #endif
  274. #ifdef GDBM
  275.     (void) sprintf (tmpfile, "%s$.gdbm", dbfile);
  276. #else
  277.     (void) sprintf (tmpfile, "%s$", dbfile);
  278. #endif
  279.     return (dbfinit (tmpfile));
  280.     }
  281.  
  282.     return (dbfinit (dbfile));
  283. }
  284.  
  285.  
  286.  
  287.  
  288. static theend (new)               /* cleanup the dbm files */
  289. int             new;
  290. {
  291.     char        fromfile [100],
  292.         tofile [100];
  293.  
  294.  
  295.     dbfclose();
  296.  
  297.     /* -- started with fresh files -- */
  298.  
  299.     if (new) {
  300.     if (Verbose || Debug)
  301.         fprintf (stderr, "Moving to database:  %s\n", dbfile);
  302.  
  303. #ifdef GDBM
  304.     (void) sprintf (fromfile, "%s$.gdbm", dbfile);
  305.     (void) sprintf (tofile, "%s.gdbm", dbfile);
  306.     if (Debug)
  307.         fprintf (stderr, "moving '%s'\n", fromfile);
  308.     if (rename (fromfile, tofile) == NOTOK)
  309.         adios (tofile, "could not rename %s to ", fromfile);
  310. #else
  311.     (void) sprintf (fromfile, "%s$.pag", dbfile);
  312.  
  313.     (void) sprintf (tofile, "%s.pag", dbfile);
  314.  
  315.     if (Debug)
  316.         fprintf (stderr, "moving '%s'\n", fromfile);
  317.  
  318.     (void) unlink (tofile);
  319.  
  320.     /* -- create and/or zero the file -- */
  321.  
  322.     if (rename (fromfile, tofile ) < 0 )
  323.         adios (tofile, "could not rename %s to ", fromfile);
  324.  
  325.     (void) sprintf (fromfile, "%s$.dir", dbfile);
  326.  
  327.     (void) sprintf (tofile, "%s.dir", dbfile);
  328.  
  329.     if (Debug)
  330.         fprintf (stderr, "moving '%s'\n", fromfile);
  331.  
  332.     (void) unlink (tofile);
  333.  
  334.     /* -- create and/or zero the file -- */
  335.  
  336.     if (rename (fromfile, tofile ) == NOTOK)
  337.         adios (tofile, "could not rename %s to ", fromfile);
  338. #endif
  339.  
  340.     return (TRUE);
  341.     }
  342.  
  343.     return (TRUE);
  344. }
  345.  
  346.  
  347.  
  348.  
  349. /*
  350. Initialize the dbm file. Fetch the local name datum
  351. Init to 1 and store it if there is no datum by that name.
  352. */
  353.  
  354. static dbfinit (filename)
  355. char    *filename;
  356. {
  357. #ifdef GDBM
  358.     if ((thedb = gdbm_open (filename, 0, GDBM_NEWDB, 0644, NULL)) == NULL)
  359. #else
  360. #ifdef NDBM
  361.     if ((thedb = dbm_open (filename, O_CREAT|O_RDWR, 0644)) == NULL)
  362. #else
  363.     if (dbminit (filename) < 0)
  364. #endif
  365. #endif
  366.         adios (filename, "could not initialize data base");
  367.     return (1);
  368. }
  369.  
  370.  
  371.  
  372.  
  373. /*
  374. Close the dbm datafile.
  375. Can't close the file because the library does not provide the call...
  376. */
  377.  
  378. static dbfclose()
  379. {
  380. #ifdef NDBM
  381.     dbm_close (thedb);
  382. #endif
  383. #ifdef GDBM
  384.     gdbm_close (thedb);
  385. #endif
  386. }
  387.  
  388.  
  389.  
  390.  
  391. /*
  392. Process a sequential file and insert items into the database
  393. Opens argument assumes database is initialized.
  394. */
  395.  
  396. static process (tp)
  397. Table           *tp;
  398. {
  399.     datum       key,
  400.         value;
  401.     char        tbkey [LINESIZE],
  402.         tbvalue [LINESIZE],
  403.         *cp;
  404.     int status;
  405.  
  406.     if (tp == NULLTBL)
  407.     return;
  408.  
  409.     if (Verbose || Debug)
  410.     fprintf (stderr, tp -> tb_fp == (FILE *)EOF ?
  411.             "%s (%s) already done\n" : "%s (%s)\n",
  412.             tp -> tb_show, tp -> tb_name);
  413.  
  414.     if (tp -> tb_fp == (FILE *)EOF)
  415.     return;
  416.  
  417.  
  418.     /* -- gain access to a channel table -- */
  419.  
  420.     if (!tb_open (tp)) {
  421.     fprintf (stderr, "could not open table \"%s\" (%s, file = '%s'):\n\t",
  422.             tp -> tb_show, tp -> tb_name,
  423.             tp -> tb_file);
  424.     perror ("");
  425.  
  426.     /* -- don't try again -- */
  427.     tp -> tb_fp = (FILE *)EOF;
  428.  
  429.     if (keepgoing)
  430.         return;
  431.     cleanup (NOTOK);
  432.     }
  433.  
  434.  
  435.     tbkey[0] = tbvalue[0] = '\0';
  436.     while ((status = tab_fetch (tp -> tb_fp, tbkey, tbvalue)) != DONE) {
  437.  
  438.     if (status == NOTOK) {
  439.         if (!keepgoing)
  440.             adios (NULLCP, "Bad record in file %s (last was %s:%s)",
  441.                  tp -> tb_name, tbkey, tbvalue);
  442.         advise (NULLCP, "Bad record in file %s (last was %s:%s)", 
  443.                 tp -> tb_name, tbkey, tbvalue);
  444.         continue;
  445.     }
  446.  
  447.     value.dptr = tbvalue;
  448.     value.dsize = strlen (tbvalue) + 1;
  449.  
  450.     /* -- all keys are lower case -- */
  451.     for (cp = tbkey; *cp != 0; cp++)
  452.         *cp = uptolow (*cp);
  453.  
  454.     key.dptr = tbkey;
  455.     key.dsize = strlen (tbkey) + 1;
  456.  
  457.     if (Debug)
  458.         fprintf (stderr, " (%d)'%s': (%d)'%s'\n",
  459.              key.dsize, key.dptr, value.dsize, value.dptr);
  460.  
  461.     install (key, value, tp -> tb_name);
  462.     }
  463.  
  464.     if (ferror (tp -> tb_fp))
  465.     advise ("", "i/o error with table %s (%s, file = %s)",
  466.                 tp -> tb_show, tp -> tb_name,
  467.                 tp -> tb_file);
  468.  
  469.     (void) tb_close (tp);
  470.  
  471.     /* -- don't try again -- */
  472.     tp -> tb_fp = (FILE *)EOF;
  473. }
  474.  
  475.  
  476.  
  477.  
  478. /*
  479. Install a datum into the database.
  480. Fetch entry first to see if we have to append name for building entry.
  481. */
  482.  
  483. static install (key, value, tbname)
  484. datum           key,
  485.         value;
  486. char            tbname[];
  487. {
  488.     datum       old;
  489.     char        newentry [ENTRYSIZE],
  490.         *p,
  491.         *q;
  492.  
  493.     p = newentry;
  494.  
  495.     old = fetch (key);
  496.  
  497.     if (old.dptr != NULLCP) {
  498.     if (Debug) {
  499.         fprintf (stderr, "\tFound old entry\n\t");
  500.         prdatum (old);
  501.     }
  502.     for (p = newentry, q = old.dptr ; *p++ = *q++;);
  503.     *(p-1) = FS;
  504.     }
  505.     else
  506.     *p = '\0';
  507.  
  508.     (void) sprintf (p, "%s %s", tbname, value.dptr);
  509.  
  510.     old.dptr = newentry;
  511.     old.dsize = strlen (newentry)+1;
  512.  
  513.     if (Debug) {
  514.     fprintf (stderr, "\tNew datum\n\t");
  515.     prdatum (old);
  516.     }
  517.  
  518.  
  519.     /* -- put the datum back -- */
  520.  
  521.     if (store (key, old) < 0) {
  522.     advise ("",
  523.         "store failed; key='%s'", key.dptr);
  524.     prdatum (old);
  525.     cleanup (NOTOK);
  526.     }
  527.  
  528. }
  529.  
  530.  
  531.  
  532.  
  533. /*
  534. Print a datum.
  535. Takes the datum arg & prints it so it can be read as either a key or entry.
  536. */
  537.  
  538. static prdatum (value)
  539. datum           value;
  540. {
  541.     int     cnt;
  542.     char    data [512];
  543.  
  544.     (void) strcpy (data, value.dptr);
  545.  
  546.     for (cnt = 0; cnt < value.dsize; cnt++) {
  547.         if (value.dptr [cnt] >= ' ' && value.dptr [cnt] <= '~')
  548.             putc (value.dptr [cnt], stderr);
  549.         else
  550.             fprintf (stderr, "<\\%03o>", value.dptr [cnt]);
  551.     }
  552.  
  553.     putc ('\n', stderr);
  554. }
  555.  
  556.  
  557.  
  558.  
  559. static check (tp)
  560. Table   *tp;
  561. {
  562.  
  563.     /* -- its bad -- */
  564.     if (tp == NULLTBL) {
  565.     if (Debug)
  566.         fprintf (stderr, "check's tp is NULL\n");
  567.     return (1);
  568.     }
  569.  
  570.     if (tp->tb_fp == (FILE *)EOF) {
  571.     if (Debug)
  572.         fprintf (stderr, "check's tp has a EOF FILE \n");
  573.     return (1);
  574.     }
  575.  
  576.     /* -- gain access to a channel table -- */
  577.     if (!tb_open (tp)) {
  578.     advise ("", "could not open table \"%s\" (%s, file = '%s')",
  579.         tp -> tb_show, tp -> tb_name, tp -> tb_file);
  580.     tp -> tb_fp = (FILE *)EOF;
  581.     return (1);
  582.     }
  583.  
  584.     (void) tb_close (tp);
  585.     tp -> tb_fp = NULLFILE;
  586.     return (0);
  587. }
  588.  
  589.  
  590.  
  591.  
  592. static void     cleanup (exitval)
  593. int     exitval;
  594. {
  595.     exit (exitval == TRUE? 0 : 1);  /* TRUE is non-zero */
  596. }
  597.  
  598. /* -------------  Basic  File  Action  ------------------------------------ */
  599.  
  600. static tb_open (tp)
  601. register Table  *tp;   /* -- table's state information -- */
  602. {
  603.     char        temppath [128];
  604.  
  605.  
  606.     /*
  607.     currently, there is one file (descriptor) per table.  for a large
  608.     configuration, you will run out of fd's.  until/unless you run
  609.     a single-file dbm-based version, there is a hack, below, which
  610.     limits the number of open file-descriptors to 6.  Trying to open
  611.     a 7th will cause a currently-opened one to be closed.
  612.     */
  613.  
  614.     if (tp == NULLTBL) {
  615.     if (Debug)
  616.         fprintf (stderr, "tb_open's table is NULL\n");
  617.     return (FALSE);
  618.     }
  619.  
  620.     if (tb_nopen < 6 || tb_free()) {
  621.  
  622.     getfpath (tbldfldir, tp -> tb_file, temppath);
  623.  
  624.     /* -- add on directory portion -- */
  625.     if ((tp -> tb_fp = fopen (temppath, "r")) != NULLFILE) {
  626.         tb_nopen++;
  627.         return (TRUE);
  628.     }
  629.     }
  630.  
  631.     printf ("cannot open %s\n", temppath);
  632.  
  633.     return (FALSE);
  634. }
  635.  
  636.  
  637.  
  638.  
  639. static tb_close (tp)
  640. register Table  *tp;
  641. {
  642.     if (tp -> tb_fp == (FILE *)NOTOK || tp -> tb_fp == NULLFILE)
  643.         return (FALSE);
  644.  
  645.     (void) fclose (tp -> tb_fp);
  646.  
  647.     /* -- mark as free -- */
  648.     tp -> tb_fp = 0;
  649.  
  650.     tb_nopen--;
  651.  
  652.     return (TRUE);
  653. }
  654.  
  655.  
  656.  
  657.  
  658. static tb_free()   /* -- create a free file descriptor -- */
  659. {
  660.     register Table      **tpp;
  661.  
  662.     /*
  663.     step from the lowest search priority to the highest, looking for a
  664.     channel to close.  return success as soon as one is done.
  665.     */
  666.  
  667.     for (tpp = tb_all; *tpp != 0; tpp++) {
  668.     if (tb_close (*tpp))
  669.         return (TRUE);   /* -- got a channel closed -- */
  670.     }
  671.     return (FALSE);   /* -- couldn't get any closed -- */
  672. }
  673.  
  674.  
  675. #ifndef lint
  676. static void    _advise ();
  677.  
  678.  
  679. void    adios (va_alist)
  680. va_dcl
  681. {
  682.     va_list ap;
  683.  
  684.     va_start (ap);
  685.  
  686.     _advise (ap);
  687.  
  688.     va_end (ap);
  689.  
  690.     _exit (1);
  691. }
  692. #else
  693. /* VARARGS */
  694.  
  695. void    adios (what, fmt)
  696. char   *what,
  697.        *fmt;
  698. {
  699.     adios (what, fmt);
  700. }
  701. #endif
  702.  
  703.  
  704. #ifndef lint
  705.  
  706. void    advise (va_alist)
  707. va_dcl
  708. {
  709.     va_list ap;
  710.  
  711.     va_start (ap);
  712.  
  713.     _advise (ap);
  714.  
  715.     va_end (ap);
  716. }
  717.  
  718. static void  _advise (ap)
  719. va_list ap;
  720. {
  721.     char    buffer[BUFSIZ];
  722.  
  723.     asprintf (buffer, ap);
  724.  
  725.     (void) fflush (stdout);
  726.  
  727.     fprintf (stderr, "%s: ", myname);
  728.     (void) fputs (buffer, stderr);
  729.     (void) fputc ('\n', stderr);
  730.  
  731.     (void) fflush (stderr);
  732. }
  733. #else
  734. /* VARARGS */
  735.  
  736. void    advise (what, fmt)
  737. char   *what,
  738.        *fmt;
  739. {
  740.     advise (what, fmt);
  741. }
  742. #endif
  743.